package de.homer.server.service;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import javax.servlet.ServletContext;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import de.homer.adapter.domain.PluginMetaInformation;
import de.homer.adapter.interfaces.HomeRPlugin;
import de.homer.persistence.adapter.PluginRepository;
import de.homer.server.util.PluginClassLoader;
import de.homer.server.util.PluginClassLoadingException;

/**
 * @author André Stannek
 * 
 */
@Service
public class PluginScanner {

	/**
	 * 
	 */
	@Autowired(required = false)
	private ServletContext context;

	/**
	 * 
	 */
	@Autowired
	private PluginClassLoader pluginClassLoader;

	/**
	 * 
	 */
	@Autowired
	private PluginRepository pluginRepository;

	/**
	 * @return all plugins found in the plugin folder
	 */
	public final Set<PluginMetaInformation> findPlugins() {
		Set<PluginMetaInformation> foundPlugins = new HashSet<>();

		if (context != null) {
			File pluginFolder = new File(context.getRealPath(""), "plugins");
			if (pluginFolder.exists()) {
				for (File file : pluginFolder.listFiles()) {
					if (file.isFile()) {
						if (file.getName().endsWith(".jar")) {
							foundPlugins.addAll(searchJarForPlugins(file));
						}
					}
				}
			}
		}

		return foundPlugins;

	}

	/**
	 * @param file
	 *            a {@link File} object pointing to a .jar file.
	 * @return all HomeRAdapter found in the given jar that are not abstract.
	 */
	private Set<PluginMetaInformation> searchJarForPlugins(final File file) {
		Set<PluginMetaInformation> foundPlugins = new HashSet<>();
		try (JarFile jarFile = new JarFile(file)) {
			Enumeration<JarEntry> entries = jarFile.entries();
			JarEntry jarEntry = null;

			while (entries.hasMoreElements()) {

				jarEntry = entries.nextElement();
				if ((jarEntry.getName().endsWith(".class"))) {
					String className = jarEntry.getName()
							.replaceAll("/", "\\.").replaceAll("\\.class", "");
					try {
						Class<? extends HomeRPlugin> clazz = pluginClassLoader
								.loadPluginClass(className, file);
						if (clazz != null) {
							PluginMetaInformation descriptor = clazz
									.newInstance().getMetaInformation();
							descriptor.setJarPath(file.getAbsolutePath());
							foundPlugins.add(descriptor);
							pluginRepository.merge(descriptor);
						}
					} catch (PluginClassLoadingException
							| InstantiationException | IllegalAccessException e) {
						Logger.getLogger("PluginClassLoading")
								.log(Level.WARN,
										"found possible plugin class but could not load it",
										e);
					}
				}
			}
		} catch (IOException e) {
			Logger.getRootLogger().log(Level.ERROR, "Could not load jar file",
					e);
		}
		return foundPlugins;
	}
}
